
// --xuezhen--
//rvcpu-test.cpp
#include <verilated.h> 
#include <verilated_vcd_c.h> 
#include <iostream>
#include <fstream>
#include "Vrvcpu.h"
#include <fstream>

using namespace std;

static Vrvcpu* top;
static VerilatedVcdC* tfp;
static vluint64_t main_time = 0;
static const vluint64_t sim_time = 3999999;

// inst.bin
// inst 0: 1 + zero = reg1 1+0=1
// inst 1: 2 + zero = reg1 2+0=2
// inst 2: 1 + reg1 = reg1 1+2=3
int inst_rom[65536];

void read_inst( char* filename)
{
  FILE *fp = fopen(filename, "rb");
  if( fp == NULL ) {
		printf( "Can not open this file!\n" );
		exit(1);
  }
  
  fseek(fp, 0, SEEK_END);
  size_t size = ftell(fp);
  fseek(fp, 0, SEEK_SET);
  size = fread(inst_rom, size, 1, fp);
  fclose(fp);
}

int main(int argc, char **argv)
{
	// char filename[100] = "../am-kernels/tests/cpu-tests/build/switch-riscv64-mycpu.bin";
	char filename[100] = "../testvector/testcopy.bin";
	// printf("Please enter your filename~\n");
	// cin >> filename;
	read_inst(filename);
	// std::cout << inst_rom[0x3d1>>2] << std::endl;
	// for(int i=0x488; i<=0x488+10*4; i+=4) std::cout << inst_rom[i>>2] << std::endl;


	// Data cache
	long int data_rom[65535] = {};
	// data_rom[0] = 6;
	// data_rom[1] = 5;
	// data_rom[2] = 4;


	// initialization
	Verilated::commandArgs(argc, argv);
	Verilated::traceEverOn(true);

	top = new Vrvcpu;
	tfp = new VerilatedVcdC;

	// if_stage = top->if_stage;

	top->trace(tfp, 99);
	tfp->open("top.vcd");
		
		long int pc_hist[4] = {0,0,0,0};
		long int pc_hist_count = 0;
		int is_stop = 0;
		while( !Verilated::gotFinish() && main_time < sim_time )
		{
			if( main_time % 10 == 0 ) top->clk = 0;
			if( main_time % 10 == 5 ) top->clk = 1;
				
			if( main_time < 10 ){
				top->rst = 1;
			}
			else
			{
				top->rst = 0;
				if(((top->inst_addr-2147483648) >> 2) >= 65535) {
					std::cout << "WWWWWWWWWWWWWWWWWW " << main_time  << " " << ((top->inst_addr-2147483648) >> 2)<< std::endl;

					std::cout << "1: "<< inst_rom[(0x9000-16-8)>>2] << std::endl;
					std::cout << inst_rom[(0x9000-16-8+4)>>2] << std::endl;
				}
				if( main_time % 10 == 5 )
				//   top->inst = (top->inst_ena == 2) ? inst_rom[ (top->inst_addr) >> 2 ] : 0;
				top->inst = inst_rom[ (top->inst_addr-2147483648) >> 2 ];
				// top->dmem_r_data = top->dmem_r_ena ? data_rom[(top->dmem_r_addr-2147483648)>>3] : 0;
				// if(top->dmem_w_ena) data_rom[(top->dmem_w_addr-2147483648)>>3] = top->dmem_w_data;
				if (top->dmem_r_ena){
					if(((top->dmem_r_addr-2147483648) >> 2) >= 65535){
						std::cout << "rrrrrrrrrrrrrrrr " << main_time  << " " << ((top->dmem_r_addr-2147483648) >> 2)<< std::endl;
						top->dmem_r_data = 0; 
					}
					else{
						long unsigned int data = 0;
						data += (long unsigned int)inst_rom[(((top->dmem_r_addr-2147483648)>>3)<<1)];
						data = data & 4294967295UL;
						data += ((long unsigned int)inst_rom[(((top->dmem_r_addr-2147483648)>>3)<<1)+1])<<32;
						top->dmem_r_data = data; 
					}
				}
				if(top->dmem_w_ena) {
					if(((top->dmem_w_addr-2147483648) >> 2) >= 65535) std::cout << "wwwwwwwwwwwwwwww " << main_time  << " " << ((top->dmem_r_addr-2147483648) >> 2)<< std::endl;
					unsigned int h, l;
					l = top->dmem_w_data & (4294967295);
					h = top->dmem_w_data >> 32;
					inst_rom[(((top->dmem_w_addr-2147483648)>>3)<<1)] = l;
					inst_rom[(((top->dmem_w_addr-2147483648)>>3)<<1)+1] = h;
				}
			}


			// if(top->is_x9 == 1) std::cout << main_time << " " << std::endl;
			// if(top->inst_addr == 0x80000010) std::cout << main_time << " " << std::endl;
			
			if( main_time % 10 == 6 ){
				pc_hist[3] = pc_hist[2];
				pc_hist[2] = pc_hist[1];
				pc_hist[1] = pc_hist[0];
				pc_hist[0] = top->inst_addr;
				if(pc_hist[0]==pc_hist[2] && pc_hist[1]==pc_hist[3]) pc_hist_count += 1;
				else pc_hist_count = 0;
				if(pc_hist_count == 100){
					is_stop = 1;
					break;
				} 
			}

			top->eval();
			tfp->dump(main_time);
			main_time++;

		}

		ofstream file_pc;
		file_pc.open("stop_pc.txt");
		if(is_stop==1) file_pc << pc_hist[0];
		else file_pc << 0;
		file_pc.close();

	// std::cout << data_rom[]
			
	// clean
	tfp->close();
	
	delete top;
	delete tfp;
	exit(0);
	return 0;
}
